package control;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import adapters.Adapter;

public class ControlService {
	public String Call(String flowName, String paramXmlString){ 
		try {
			String flowResponseXML = "<?xml version='1.0' encoding='utf-8'?><flow name='" + flowName + "' >";
			String responseXML = "";
			String[] s = getWebServices(flowName);
			for (int i=0;i<s.length;i++){
				
				responseXML = callWebService(s[i],paramXmlString);
				flowResponseXML += responseXML;

				if (s.length>1){
					DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
					DocumentBuilder builder=factory.newDocumentBuilder();
					Document doc = builder.parse(new ByteArrayInputStream(responseXML.getBytes("utf8")));
					NodeList responseNodeList = doc.getElementsByTagName("response");
					String status = ((Element)responseNodeList.item(0)).getAttribute("name");
					if (status.equals("fail")){
						break;
					}else{
//						paramXmlString = "";
						for (int j=1;j<responseNodeList.getLength();j++){
							paramXmlString +="<param name='"+((Element)responseNodeList.item(j)).getAttribute("name")+"' ";
							paramXmlString +="value='"+((Element)responseNodeList.item(j)).getAttribute("value")+"' />";
						}
					}
				}
			}
			flowResponseXML += "</flow>";
			return flowResponseXML;
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private void saveXMLtoFile(String fileName,String xml){
		try {
			FileOutputStream fo = new FileOutputStream(new File("D:\\temp\\"+fileName+".xml"));
			fo.write(xml.getBytes("utf8"));
			fo.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	// return names of all webservices of a specified flow
	private String[] getWebServices(String flowName){
		try {
			DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
			DocumentBuilder builder=factory.newDocumentBuilder();
			InputStream is =getClass().getClassLoader().getResourceAsStream("configs/flows.xml");
			Document doc = builder.parse(is);
			NodeList flowNodeList = doc.getElementsByTagName("flow");
			for (int i=0;i<flowNodeList.getLength();i++){
				Element flowNode = (Element)flowNodeList.item(i);
				if (flowName.equals(flowNode.getAttributeNode("name").getValue())){
					NodeList wsNodeList = flowNode.getElementsByTagName("webservice");
					int l = wsNodeList.getLength();
					String[] webServices = new String[l];
					for (int j=0;j<l;j++){
						webServices[j] = wsNodeList.item(j).getAttributes().item(0).getNodeValue();
					}
					return webServices;
				}
			}
		} catch (DOMException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	// call the specified webservice
	public String callWebService(String webServiceName,String paramXmlString){
		try {
			DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
			DocumentBuilder builder=factory.newDocumentBuilder();
			InputStream is =getClass().getClassLoader().getResourceAsStream("configs/webServices.xml");
			Document doc = builder.parse(is);
			NodeList webServiceNodeList = doc.getElementsByTagName("webService");
			for (int i=0;i<webServiceNodeList.getLength();i++){
				Element webServiceElement = (Element)webServiceNodeList.item(i);
				String name = webServiceElement.getElementsByTagName("name").item(0).getFirstChild().getNodeValue();
				if (!webServiceName.equals(name)) continue;
				
				String xmlString = "<?xml version='1.0' encoding='utf-8' ?>"+"<webService name='"+webServiceName+"'>"
									+paramXmlString+"</webService>";
//				saveXMLtoFile(name+"_request", xmlString);
				String adapterName = webServiceElement.getElementsByTagName("adapterClass").item(0).getFirstChild().getNodeValue();
				Class adapterClass = Class.forName(adapterName);
				Adapter adapter = (Adapter)adapterClass.newInstance();
				return adapter.callWebService(xmlString);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;	
	}
	
	public static void main(String args[]){
//		System.out.println(new ControlService().Call("newuser",
//				"<param name='username' value='小民' />" 
//				+"<param name='password' value='xiaomin' />"
//				+"<param name='email' value='xiaoming@163.com' />"));
//		System.out.println(new ControlService().Call("loginuser","<param name='username' value='???è?????' />" 
//				+"<param name='password' value='111111' />"
//				+"<param name='email' value='xiaoming@163.com' />"));
//		System.out.println(new ControlService().Call("browsebook",
//				"<param name='saletype' value='normal' />" ));
		System.out.println(new ControlService().Call("makeorder",
						"<param name='book'><bookid>1</bookid><quantity>5</quantity></param>"
					   +"<param name='book'><bookid>2</bookid><quantity>3</quantity></param>"
					   +"<param name='userid' value='11' />"
					   +"<param name='orderAddress' value='SE,NJU' />"
					   +"<param name='orderTime' value='20070430' />"));
//		System.out.println(new ControlService().Call("payanddeliver",
//						"<param name='orderid' value='2'/>"
//					   +"<param name='accountid' value='9999' />"));
	}
}
